home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / 3Dmodeling / solids.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  17.5 KB  |  638 lines

  1. /*
  2.  * Copyright 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17.  
  18. /* Routines to build 3 dimensional solids.
  19.  *
  20.  *  -- Tom Davis 1990
  21.  *
  22.  * Exported routines include:
  23.  *
  24.  * drawbox, quadsphere, doughnut, elbow, cylinder, trisphere,
  25.  * icosahedron, octahedron, tetrahedron, dodecahedron.
  26.  *
  27.  * Some documentation appears above each routine.
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <math.h>
  32. #include "3d.h"
  33.  
  34. void drawbox(float x0, float x1, float y0, float y1,
  35.         float z0, float z1, void (*savefunc)());
  36. static void drawtriangle(long i, long type, long depth,
  37.             float p0[3], float radius, long avnormal);
  38. static void recorditem(float *n1, float *n2, float *n3,
  39.         float center[3], float radius, long avnormal);
  40.  
  41.  
  42. #define PI    3.1415926535897
  43. #define EPSILON    .0001
  44.  
  45. float cv[8][3];
  46. float cnorms[6][3] = {
  47.     {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
  48.     {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}
  49. };
  50.  
  51. long faces[6][4] = {
  52.     { 0, 1, 2, 3 }, { 3, 2, 6, 7 }, { 7, 6, 5, 4 },
  53.     { 4, 5, 1, 0 }, { 5, 6, 2, 1 }, { 7, 4, 0, 3 }
  54. };
  55.  
  56. /* drawbox:
  57.  *
  58.  * draws a cubical box with the given x, y, and z ranges.  The box is
  59.  * axis-aligned.
  60.  */
  61.  
  62. void drawbox(float x0, float x1, float y0, float y1,
  63.         float z0, float z1, void (*savefunc)())
  64. {
  65.     long    i;
  66.     float    temp;
  67.     float    p0[3], p1[3], p2[3], p3[3];
  68.     float    n0[3], n1[3], n2[3], n3[3];
  69.  
  70.     if (x0 > x1) { temp = x0; x0 = x1; x1 = temp; }
  71.     if (y0 > y1) { temp = y0; y0 = y1; y1 = temp; }
  72.     if (z0 > z1) { temp = z0; z0 = z1; z1 = temp; }
  73.     cv[0][0] = cv[1][0] = cv[2][0] = cv[3][0] = x0;
  74.     cv[4][0] = cv[5][0] = cv[6][0] = cv[7][0] = x1;
  75.     cv[0][1] = cv[1][1] = cv[4][1] = cv[5][1] = y0;
  76.     cv[2][1] = cv[3][1] = cv[6][1] = cv[7][1] = y1;
  77.     cv[0][2] = cv[3][2] = cv[4][2] = cv[7][2] = z0;
  78.     cv[1][2] = cv[2][2] = cv[5][2] = cv[6][2] = z1;
  79.     for (i = 0; i < 6; i++) {
  80.     m_xformpt(&cv[faces[i][0]][0], p0, &cnorms[i][0], n0);
  81.     m_xformpt(&cv[faces[i][1]][0], p1, &cnorms[i][0], n1);
  82.     m_xformpt(&cv[faces[i][2]][0], p2, &cnorms[i][0], n2);
  83.     m_xformpt(&cv[faces[i][3]][0], p3, &cnorms[i][0], n3);
  84.     (*savefunc)(ADD_QUAD, n0, p0, n1, p1, n2, p2, n3, p3);
  85.     }
  86. }
  87.  
  88. /* quadsphere:
  89.  *
  90.  * draws a sphere centered at 0.0 and radius 1.0.  The sphere is composed of
  91.  * quadrilaterals with latsides latitude lines and lonsides longitude lines
  92.  */
  93.  
  94. void quadsphere(long latsides, long lonsides, void (*savefunc)())
  95. {
  96.     float    theta, phi;
  97.     float    p0[3], p1[3], p2[3], p3[3];
  98.     float    n0[3], n1[3], n2[3], n3[3];
  99.     long    i;
  100.     long    lat, lon;
  101.  
  102.     for (lat = 0; lat < latsides; lat++)
  103.         for (lon = 0; lon < lonsides; lon++) {
  104.         theta = lat*PI/latsides;
  105.         phi = lon*2.0*PI/lonsides;
  106.         n0[0]= sin(theta)*cos(phi);
  107.         n0[1]= sin(theta)*sin(phi);
  108.         n0[2]= cos(theta);
  109.  
  110.         n1[0]= sin(theta+PI/latsides)*cos(phi);
  111.         n1[1]= sin(theta+PI/latsides)*sin(phi);
  112.         n1[2]= cos(theta+PI/latsides);
  113.  
  114.         n2[0]= sin(theta+PI/latsides)*cos(phi+2.0*PI/lonsides);
  115.         n2[1]= sin(theta+PI/latsides)*sin(phi+2.0*PI/lonsides);
  116.         n2[2]= cos(theta+PI/latsides);
  117.  
  118.         n3[0]= sin(theta)*cos(phi+2.0*PI/lonsides);
  119.         n3[1]= sin(theta)*sin(phi+2.0*PI/lonsides);
  120.         n3[2]= cos(theta);
  121.  
  122.         m_xformpt(n0, p0, n0, n0);
  123.         m_xformpt(n1, p1, n1, n1);
  124.         m_xformpt(n2, p2, n2, n2);
  125.         m_xformpt(n3, p3, n3, n3);
  126.  
  127.         (*savefunc)(ADD_QUAD, n0, p0, n1, p1, n2, p2, n3, p3);
  128.     }
  129. }
  130.  
  131. /* doughnut:
  132.  *
  133.  * draws a doughnut, centered at (0, 0, 0) whose axis is aligned with
  134.  * the z-axis.  The doughnut's major radius is R, and minor radius is r.
  135.  */
  136.  
  137. void doughnut(float r, float R, long nsides, long rings, void (*savefunc)())
  138. {
  139.     long    i, j;
  140.     float    theta, phi, theta1, phi1;
  141.     float    p0[03], p1[3], p2[3], p3[3];
  142.     float    n0[3], n1[3], n2[3], n3[3];
  143.  
  144.     for (i = 0; i < rings; i++) {
  145.     theta = (float)i*2.0*PI/rings;
  146.     theta1 = (float)(i+1)*2.0*PI/rings;
  147.     for (j = 0; j < nsides; j++) {
  148.         phi = (float)j*2.0*PI/nsides;
  149.         phi1 = (float)(j+1)*2.0*PI/nsides;
  150.  
  151.         p0[0] = cos(theta)*(R + r*cos(phi));
  152.         p0[1] = -sin(theta)*(R + r*cos(phi));
  153.         p0[2] = r*sin(phi);
  154.  
  155.         p1[0] = cos(theta1)*(R + r*cos(phi));
  156.         p1[1] = -sin(theta1)*(R + r*cos(phi));
  157.         p1[2] = r*sin(phi);
  158.  
  159.         p2[0] = cos(theta1)*(R + r*cos(phi1));
  160.         p2[1] = -sin(theta1)*(R + r*cos(phi1));
  161.         p2[2] = r*sin(phi1);
  162.  
  163.         p3[0] = cos(theta)*(R + r*cos(phi1));
  164.         p3[1] = -sin(theta)*(R + r*cos(phi1));
  165.         p3[2] = r*sin(phi1);
  166.  
  167.         n0[0] = cos(theta)*(cos(phi));
  168.         n0[1] = -sin(theta)*(cos(phi));
  169.         n0[2] = sin(phi);
  170.  
  171.         n1[0] = cos(theta1)*(cos(phi));
  172.         n1[1] = -sin(theta1)*(cos(phi));
  173.         n1[2] = sin(phi);
  174.  
  175.         n2[0] = cos(theta1)*(cos(phi1));
  176.         n2[1] = -sin(theta1)*(cos(phi1));
  177.         n2[2] = sin(phi1);
  178.  
  179.         n3[0] = cos(theta)*(cos(phi1));
  180.         n3[1] = -sin(theta)*(cos(phi1));
  181.         n3[2] = sin(phi1);
  182.  
  183.         m_xformpt(p0, p0, n0, n0);
  184.         m_xformpt(p1, p1, n1, n1);
  185.         m_xformpt(p2, p2, n2, n2);
  186.         m_xformpt(p3, p3, n3, n3);
  187.  
  188.         (*savefunc)(ADD_QUAD, n3, p3, n2, p2, n1, p1, n0, p0);
  189.     }
  190.     }
  191. }
  192.  
  193. /* elbow:
  194.  *
  195.  * draws an elbow of 90 degrees, centered at pt0, and passing through
  196.  * pt1 and pt2.  The tube has the given radius, sides around the tube,
  197.  * and number of segments along the tube.
  198.  *
  199.  */
  200.  
  201. void elbow(float *pt0, float *pt1, float *pt2,
  202.         float radius, long nsides, long nsegs, void (*savefunc)())
  203. {
  204.     float theta, theta1, phi, phi1;
  205.     float pv[3], pv1[3], vperp[3], diff[3];
  206.     float p0[3], p1[3], p2[3], p3[3];
  207.     float n0[3], n1[3], n2[3], n3[3];
  208.     long i;
  209.  
  210.     for (theta = 0; theta < PI/2 - EPSILON; theta += PI/(2.0*nsegs)) {
  211.     for (i = 0; i < 3; i++) {
  212.         theta1 = theta + PI/(2.0*nsegs);
  213.         pv[i] = pt1[i]+(pt0[i]-pt1[i])*cos(theta)+(pt2[i]-pt1[i])*sin(theta);
  214.         pv1[i] = pt1[i]+(pt0[i]-pt1[i])*cos(theta1)+(pt2[i]-pt1[i])*sin(theta1);
  215.     }
  216.     for (i = 0; i < 3; i++) {
  217.         p0[i] = pv[i] - pt1[i];
  218.         p1[i] = pv1[i] - pt1[i];
  219.     }
  220.     crossprod(p0, p1, vperp);
  221.     normalize(vperp);
  222.     for (phi = 0; phi < 2.0*PI - EPSILON; phi += 2.0*PI/nsides) {
  223.         phi1 = phi + 2*PI/nsides;
  224.         for (i = 0; i < 3; i++) {
  225.         diff3(pt1, pv, diff); normalize(diff);
  226.         p3[i]=pv[i]+radius*(diff[i]*cos(phi)+vperp[i]*sin(phi));
  227.         n3[i] = p3[i] - pv[i];
  228.         diff3(pt1, pv1, diff); normalize(diff);
  229.         p2[i]=pv1[i]+radius*(diff[i]*cos(phi)+vperp[i]*sin(phi));
  230.         n2[i] = p2[i] - pv1[i];
  231.         p1[i]=pv1[i]+radius*(diff[i]*cos(phi1)+vperp[i]*sin(phi1));
  232.         n1[i] = p1[i] - pv1[i];
  233.         diff3(pt1, pv, diff); normalize(diff);
  234.         p0[i]=pv[i]+radius*(diff[i]*cos(phi1)+vperp[i]*sin(phi1));
  235.         n0[i] = p0[i] - pv[i];
  236.         }
  237.         normalize(n0);
  238.         normalize(n1);
  239.         normalize(n2);
  240.         normalize(n3);
  241.  
  242.         m_xformpt(p0, p0, n0, n0);
  243.         m_xformpt(p1, p1, n1, n1);
  244.         m_xformpt(p2, p2, n2, n2);
  245.         m_xformpt(p3, p3, n3, n3);
  246.  
  247.         (*savefunc)(ADD_QUAD, n1, p1, n2, p2, n3, p3, n0, p0);
  248.     }
  249.     }
  250. }
  251.  
  252. /* cylinder:
  253.  *
  254.  * Creates rectangles around a cylinder going from pt1 to pt2.
  255.  * Each time a rectangle is created, the function savefunc() is called:
  256.  *
  257.  * savefunc(n0, v0, n1, v1, n2, v2, n3, v3);
  258.  *
  259.  * the cylinder has nsides cylinder sides at the given radius.
  260.  */
  261.  
  262. void cylinder(float *pt1, float *pt2,
  263.         float radius, long nsides, void (*savefunc)())
  264. {
  265.     long    eq = 0, i, j;
  266.     float    vperp[3], uperp[3], diff[3], n1[3], n2[3], n0[3] /* dummy */;
  267.     float    v0[3], v1[3], v2[3], v3[3];
  268.     float    theta, theta1;
  269.  
  270.     n0[0] = n0[1] = n0[2] = 0.0;
  271.     for (i = 0; i < 3; i++)
  272.     if (pt1[i] == pt2[i]) eq++;
  273.     for (i = 0; i < 3; i++)
  274.     diff[i] = pt1[i] - pt2[i];
  275.     if (eq == 2) { /* it's axis-aligned */
  276.     if (pt1[0] != pt2[0]) {
  277.         vperp[0] = vperp[2] = 0.0;
  278.         vperp[1] = 1.0;
  279.     } else if (pt1[1] != pt2[1]) {
  280.         vperp[0] = vperp[1] = 0.0;
  281.         vperp[2] = 1.0;
  282.     } else {
  283.         vperp[1] = vperp[2] = 0.0;
  284.         vperp[0] = 1.0;
  285.     }
  286.     } else { /* it's a general cylinder */
  287.     if (diff[0] == 0.0) {
  288.         vperp[0] = 0.0;
  289.         vperp[1] = 1.0;
  290.         vperp[2] = -diff[1]/diff[2];
  291.     } else if (diff[1] == 0.0) {
  292.         vperp[1] = 0.0;
  293.         vperp[0] = 1.0;
  294.         vperp[2] = - diff[0]/diff[2];
  295.     } else {
  296.         vperp[2] = 0.0;
  297.         vperp[0] = 1.0;
  298.         vperp[1] = - diff[0]/diff[1];
  299.     }
  300.     normalize(vperp);
  301.     }
  302.     crossprod(diff, vperp, uperp);
  303.     normalize(uperp);
  304.     for (theta = 0.0; theta < 2.0*PI - EPSILON; theta += 2.0*PI/nsides) {
  305.     theta1 = theta + 2.0*PI/nsides;
  306.     for (i = 0; i < 3; i++) {
  307.         n1[i] = vperp[i]*cos(theta) + uperp[i]*sin(theta);
  308.         n2[i] = vperp[i]*cos(theta1) + uperp[i]*sin(theta1);
  309.     }
  310.     v0[0] = pt1[0]+n1[0]*radius;
  311.     v0[1] = pt1[1]+n1[1]*radius;
  312.     v0[2] = pt1[2]+n1[2]*radius;
  313.     v1[0] = pt2[0]+n1[0]*radius;
  314.     v1[1] = pt2[1]+n1[1]*radius;
  315.     v1[2] = pt2[2]+n1[2]*radius;
  316.     v2[0] = pt2[0]+n2[0]*radius;
  317.     v2[1] = pt2[1]+n2[1]*radius;
  318.     v2[2] = pt2[2]+n2[2]*radius;
  319.     v3[0] = pt1[0]+n2[0]*radius;
  320.     v3[1] = pt1[1]+n2[1]*radius;
  321.     v3[2] = pt1[2]+n2[2]*radius;
  322.  
  323.     m_xformpt(v0, v0, n1, n1);
  324.     m_xformptonly(v1, v1);
  325.     m_xformpt(v2, v2, n2, n2);
  326.     m_xformptonly(v3, v3);
  327.  
  328.     (*savefunc)(ADD_QUAD, n1, v0, n1, v1, n2, v2, n2, v3);
  329.     }
  330. }
  331.  
  332. /* octahedron data: The octahedron produced is centered at the origin
  333.  * and has radius 1.0 */
  334.  
  335. static float odata[6][3] = {
  336.   {1.0, 0.0, 0.0},
  337.   {-1.0, 0.0, 0.0},
  338.   {0.0, 1.0, 0.0},
  339.   {0.0, -1.0, 0.0},
  340.   {0.0, 0.0, 1.0},
  341.   {0.0, 0.0, -1.0}
  342. };
  343.  
  344. static long ondex[8][3] = {
  345.     {0, 4, 2}, {1, 2, 4}, {0, 3, 4}, {1, 4, 3},
  346.     {0, 2, 5}, {1, 5, 2}, {0, 5, 3}, {1, 3, 5}
  347. };
  348.  
  349. /* tetrahedron data: */
  350.  
  351. #define T    1.73205080756887729
  352.  
  353. static float tdata[4][3] = {
  354.     {T, T, T}, {T, -T, -T}, {-T, T, -T}, {-T, -T, T}
  355. };
  356.  
  357. static long tndex[4][3] = {
  358.     {0, 1, 3}, {2, 1, 0}, {3, 2, 0}, {1, 2, 3}
  359. };
  360.  
  361. /* icosahedron data: These numbers are rigged to make an icosahedron
  362.  * of radius 1.0 */
  363.  
  364. #define X .525731112119133606
  365. #define Z .850650808352039932
  366.  
  367. static float idata[12][3] = {
  368.   {-X, 0, Z},
  369.   {X, 0, Z},
  370.   {-X, 0, -Z},
  371.   {X, 0, -Z},
  372.   {0, Z, X},
  373.   {0, Z, -X},
  374.   {0, -Z, X},
  375.   {0, -Z, -X},
  376.   {Z, X, 0},
  377.   {-Z, X, 0},
  378.   {Z, -X, 0},
  379.   {-Z, -X, 0}
  380. };
  381.  
  382. static long index[20][3] = {
  383.     {0, 4, 1},    {0, 9, 4},
  384.     {9, 5, 4},    {4, 5, 8},
  385.     {4, 8, 1},    {8, 10, 1},
  386.     {8, 3, 10},    {5, 3, 8},
  387.     {5, 2, 3},    {2, 7, 3},
  388.     {7, 10, 3},    {7, 6, 10},
  389.     {7, 11, 6},    {11, 0, 6},
  390.     {0, 1, 6},    {6, 1, 10},
  391.     {9, 0, 11},    {9, 11, 2},
  392.     {9, 2, 5},    {7, 2, 11},
  393. };
  394.  
  395. static void (*sfunc)();
  396.  
  397. /* trisphere:
  398.  *
  399.  * Draws a sphere of given radius centered at the point p0.
  400.  * depth controls the amount of subdivision.  If depth is 1, an
  401.  * icosahedron is drawn.  If depth is 2, each triangle is split into 4
  402.  * pieces; if depth is 3, each triangle is split into 10 pieces, etc.
  403.  * The normals generated are perpendicular to the sphere's surface.
  404.  */
  405.  
  406. void trisphere(float p0[3], float radius, long depth, void (*savefunc)())
  407. {
  408.     long i;
  409.  
  410.     if (depth < 1) depth = 1;
  411.     sfunc = savefunc;
  412.     for (i = 0; i < 20; i++)
  413.     drawtriangle(i, 0, depth, p0, radius, 1);
  414. }
  415.  
  416. /* icosahedron:
  417.  *
  418.  * Draws an icosahedron with center at p0 having the
  419.  * given radius.
  420.  */
  421.  
  422. void icosahedron(float p0[3], float radius, void (*savefunc)())
  423. {
  424.     long i;
  425.  
  426.     sfunc = savefunc;
  427.     for (i = 0; i < 20; i++)
  428.     drawtriangle(i, 0, 1, p0, radius, 0);
  429. }
  430.  
  431. /* octahedron:
  432.  *
  433.  * Draws an octahedron with center at p0 having the
  434.  * given radius.
  435.  */
  436.  
  437. void octahedron(float p0[3], float radius, void (*savefunc)())
  438. {
  439.     long i;
  440.  
  441.     sfunc = savefunc;
  442.     for (i = 0; i < 8; i++)
  443.     drawtriangle(i, 1, 1, p0, radius, 0);
  444. }
  445.  
  446. /* tetrahedron:
  447.  *
  448.  * Draws an tetrahedron with center at p0 having the
  449.  * given radius.
  450.  */
  451.  
  452. void tetrahedron(float p0[3], float radius, void (*savefunc)())
  453. {
  454.     long i;
  455.  
  456.     sfunc = savefunc;
  457.     for (i = 0; i < 4; i++)
  458.     drawtriangle(i, 2, 1, p0, radius, 0);
  459. }
  460.  
  461. static void subdivide(long depth, float *v0, float *v1, float *v2,
  462.         float p0[3], float radius, long avnormal)
  463. {
  464.     float w0[3], w1[3], w2[3];
  465.     float l;
  466.     long i, j, k, n;
  467.  
  468.     for (i = 0; i < depth; i++)
  469.     for (j = 0; i + j < depth; j++) {
  470.         k = depth - i - j;
  471.         for (n = 0; n < 3; n++) {
  472.         w0[n] = (i*v0[n] + j*v1[n] + k*v2[n])/depth;
  473.         w1[n] = ((i+1)*v0[n] + j*v1[n] + (k-1)*v2[n])/depth;
  474.         w2[n] = (i*v0[n] + (j+1)*v1[n] + (k-1)*v2[n])/depth;
  475.         }
  476.         l = sqrt(w0[0]*w0[0] + w0[1]*w0[1] + w0[2]*w0[2]);
  477.         w0[0] /= l; w0[1] /= l; w0[2] /= l;
  478.         l = sqrt(w1[0]*w1[0] + w1[1]*w1[1] + w1[2]*w1[2]);
  479.         w1[0] /= l; w1[1] /= l; w1[2] /= l;
  480.         l = sqrt(w2[0]*w2[0] + w2[1]*w2[1] + w2[2]*w2[2]);
  481.         w2[0] /= l; w2[1] /= l; w2[2] /= l;
  482.         recorditem(w1, w0, w2, p0, radius, avnormal);
  483.     }
  484.     for (i = 0; i < depth-1; i++)
  485.     for (j = 0; i + j < depth-1; j++) {
  486.         k = depth - i - j;
  487.         for (n = 0; n < 3; n++) {
  488.         w0[n] = ((i+1)*v0[n] + (j+1)*v1[n] + (k-2)*v2[n])/depth;
  489.         w1[n] = ((i+1)*v0[n] + j*v1[n] + (k-1)*v2[n])/depth;
  490.         w2[n] = (i*v0[n] + (j+1)*v1[n] + (k-1)*v2[n])/depth;
  491.         }
  492.         l = sqrt(w0[0]*w0[0] + w0[1]*w0[1] + w0[2]*w0[2]);
  493.         w0[0] /= l; w0[1] /= l; w0[2] /= l;
  494.         l = sqrt(w1[0]*w1[0] + w1[1]*w1[1] + w1[2]*w1[2]);
  495.         w1[0] /= l; w1[1] /= l; w1[2] /= l;
  496.         l = sqrt(w2[0]*w2[0] + w2[1]*w2[1] + w2[2]*w2[2]);
  497.         w2[0] /= l; w2[1] /= l; w2[2] /= l;
  498.         recorditem(w0, w1, w2, p0, radius, avnormal);
  499.     }
  500. }
  501.  
  502. static void drawtriangle(long i, long type, long depth,
  503.             float p0[3], float radius, long avnormal)
  504. {
  505.     float *x0, *x1, *x2;
  506.  
  507.     switch (type) {
  508.     case 0:    /* icosahedron */
  509.         x0 = &idata[index[i][0]][0];
  510.         x1 = &idata[index[i][1]][0];
  511.         x2 = &idata[index[i][2]][0];
  512.         break;
  513.     case 1: /* octahedron */
  514.         x0 = &odata[ondex[i][0]][0];
  515.         x1 = &odata[ondex[i][1]][0];
  516.         x2 = &odata[ondex[i][2]][0];
  517.         break;
  518.     case 2: /* tetrahedron */
  519.         x0 = &tdata[tndex[i][0]][0];
  520.         x1 = &tdata[tndex[i][1]][0];
  521.         x2 = &tdata[tndex[i][2]][0];
  522.         break;
  523.     }
  524.     subdivide(depth, x0, x1, x2, p0, radius, avnormal);
  525. }
  526.  
  527. static void recorditem(float *n1, float *n2, float *n3,
  528.         float center[3], float radius, long avnormal)
  529. {
  530.     float    p1[3], p2[3], p3[3], q0[3], q1[3], n11[3], n22[3], n33[3];
  531.     long    i;
  532.  
  533.     for (i = 0; i < 3; i++) {
  534.     p1[i] = n1[i]*radius + center[i];
  535.     p2[i] = n2[i]*radius + center[i];
  536.     p3[i] = n3[i]*radius + center[i];
  537.     }
  538.     if (avnormal == 0) {
  539.     diff3(p1, p2, q0);
  540.     diff3(p2, p3, q1);
  541.     crossprod(q0, q1, q1);
  542.     normalize(q1);
  543.     m_xformpt(p1, p1, q1, n11);
  544.     m_xformptonly(p2, p2);
  545.     m_xformptonly(p3, p3);
  546.  
  547.     (*sfunc)(ADD_TRI, n11, p1, n11, p2, n11, p3);
  548.     return;
  549.     }
  550.     m_xformpt(p1, p1, n1, n11);
  551.     m_xformpt(p2, p2, n2, n22);
  552.     m_xformpt(p3, p3, n3, n33);
  553.  
  554.     (*sfunc)(ADD_TRI, n11, p1, n22, p2, n33, p3);
  555. }
  556.  
  557. float dodec[20][3];
  558.  
  559. static void initdodec()
  560. {
  561.     float alpha, beta;
  562.  
  563.     alpha = sqrt(2.0/(3.0 + sqrt(5.0)));
  564.     beta = 1.0 + sqrt(6.0/(3.0 + sqrt(5.0)) - 2.0 + 2.0*sqrt(2.0/(3.0 +
  565.                                 sqrt(5.0))));
  566.     dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
  567.     dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
  568.     dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
  569.     dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
  570.     dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
  571.     dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
  572.     dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
  573.     dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
  574.     dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
  575.     dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
  576.     dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
  577.     dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
  578.     dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
  579.     dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
  580.     dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
  581.     dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
  582.     dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
  583.     dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
  584.     dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
  585.     dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
  586. }
  587.  
  588. /* dodecahedron:
  589.  *
  590.  * Draws an dodecahedron with center at 0.0. The radius
  591.  * is sqrt(3).
  592.  */
  593.  
  594. void dodecahedron(float center[3], float sc, void (*savefunc)())
  595. {
  596.     static long inited = 0;
  597.  
  598.     if ( inited == 0) {
  599.     inited = 1;
  600.     initdodec();
  601.     }
  602.     m_pushmatrix();
  603.     m_translate(center[0], center[1], center[2]);
  604.     m_scale(sc, sc, sc);
  605.     sfunc = savefunc;
  606.     pentagon(0, 1, 9, 16, 5);
  607.     pentagon(1, 0, 3, 18, 7);
  608.     pentagon(1, 7, 11, 10, 9);
  609.     pentagon(11, 7, 18, 19, 6);
  610.     pentagon(8, 17, 16, 9, 10);
  611.     pentagon(2, 14, 15, 6, 19);
  612.     pentagon(2, 13, 12, 4, 14);
  613.     pentagon(2, 19, 18, 3, 13);
  614.     pentagon(3, 0, 5, 12, 13);
  615.     pentagon(6, 15, 8, 10, 11);
  616.     pentagon(4, 17, 8, 15, 14);
  617.     pentagon(4, 12, 5, 16, 17);
  618.     m_popmatrix();
  619. }
  620.  
  621. static void pentagon(long a, long b, long c, long d, long e)
  622. {
  623.     float n0[3], d1[3], d2[3], d3[3], d4[3], d5[3], nout[3];
  624.  
  625.     diff3(&dodec[a][0], &dodec[b][0], d1);
  626.     diff3(&dodec[b][0], &dodec[c][0], d2);
  627.     crossprod(d1, d2, n0);
  628.     normalize(n0);
  629.     m_xformpt(&dodec[a][0], d1, n0, nout);
  630.     m_xformptonly(&dodec[b][0], d2);
  631.     m_xformptonly(&dodec[c][0], d3);
  632.     m_xformptonly(&dodec[d][0], d4);
  633.     m_xformptonly(&dodec[e][0], d5);
  634.     (*sfunc)(ADD_TRI, nout, d1, nout, d2, nout, d3);
  635.     (*sfunc)(ADD_TRI, nout, d1, nout, d3, nout, d4);
  636.     (*sfunc)(ADD_TRI, nout, d1, nout, d4, nout, d5);
  637. }
  638.